#include <iostream>
#include <math.h>
using namespace std;
typedef union {unsigned long long int aux; unsigned int a[2];} Tunion;

unsigned int kk; // Global
void D(unsigned int * u, unsigned int n, unsigned int & r){
unsigned int j;
Tunion U;
const unsigned int v = /*5^13*/ 1220703125;
r = 0;
while(u[kk] == 0) kk++;
j = kk;
S2: U.a[1] = r; U.a[0] = u[j]; u[j] = U.aux / v; r = U.aux - u[j] * v; j++;
if(j <= n) goto S2;
}

/*
    The function LastDigit(N, nD2A32) finds the last nonzero digit of N!. The
input is N in base b = 2^32, and nD2A32 which is the number of digits of N in
base b.

Example of usage of LastDigit()
    This program calls LastDigit() with N = 2^p[i]-1, 1=<i<=47. The number of
digits of N in base b, nD2A32, is equal to [p[i]/32]+1.

N has at most floor(p[47]/32)+1 = 1347270 digits. (Table p is given below.)
*/

unsigned int LastDigit(unsigned int*N, unsigned int nD2A32){
unsigned int t, m, r, aux, z, L, R[13], q;
t = 0; m = 0;
kk = 1;
do{
    D(N, nD2A32, r);
    aux = r; r = r/5; z = aux - 5*r;
    if((z & 1) == 0) t += z;
    for(L = 12; L >= 1; L--){
        aux = r; r = r/5; R[L] = aux - 5*r;
        if((R[L] & 1) == 0)
            t += R[L];
            }
    q = N[nD2A32] & 3; m += q;
    for(L = 1; L <= 12; L++){
        q = (5*q + R[L]) & 3;
        m += q;
        }
    if(N[nD2A32] == 0)
        break;
    }while(true);
z = (m + t/2) % 4;
if(z == 0) return 6;
else return pow(2, z);
}

const unsigned int nMaxTerms = 47;
const unsigned int p[nMaxTerms + 1] =
{0,2,3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, 3217,
 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503,
 132049, 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593,
 13466917, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, 42643801,
 43112609};

void DetPow2_1(unsigned int * pow2_1){ // 2^i-1 for i=1...31
unsigned int i, j = 1;
for(i = 1; i <= 31; i++){ j *= 2; pow2_1[i] = j - 1; }
}

int main(){
unsigned int * N, nD2A32, i, j, pow2_1[32], ld;
DetPow2_1(pow2_1);
N = new unsigned int[1347270 + 1];
for(i = 1; i <= nMaxTerms; i++){
    nD2A32 =  p[i]/32 + 1;
    N[1] = pow2_1[p[i] % 32];
    for(j = 2; j <= nD2A32; j++) N[j] = 4294967295U;
    ld = LastDigit(N, nD2A32);
    cout << ld << ", ";
    }
delete[] N; return 0;
}
